1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.util;
21
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26
27 /**
28 * A thread-safe version of {@link Map} in which all operations that change the
29 * Map are implemented by making a new copy of the underlying Map.
30 *
31 * While the creation of a new Map can be expensive, this class is designed for
32 * cases in which the primary function is to read data from the Map, not to
33 * modify the Map. Therefore the operations that do not cause a change to this
34 * class happen quickly and concurrently.
35 *
36 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
37 */
38 public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
39 private volatile Map<K, V> internalMap;
40
41 /**
42 * Creates a new instance of CopyOnWriteMap.
43 *
44 */
45 public CopyOnWriteMap() {
46 internalMap = new HashMap<K, V>();
47 }
48
49 /**
50 * Creates a new instance of CopyOnWriteMap with the specified initial size
51 *
52 * @param initialCapacity
53 * The initial size of the Map.
54 */
55 public CopyOnWriteMap(int initialCapacity) {
56 internalMap = new HashMap<K, V>(initialCapacity);
57 }
58
59 /**
60 * Creates a new instance of CopyOnWriteMap in which the
61 * initial data being held by this map is contained in
62 * the supplied map.
63 *
64 * @param data
65 * A Map containing the initial contents to be placed into
66 * this class.
67 */
68 public CopyOnWriteMap(Map<K, V> data) {
69 internalMap = new HashMap<K, V>(data);
70 }
71
72 /**
73 * Adds the provided key and value to this map.
74 *
75 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
76 */
77 public V put(K key, V value) {
78 synchronized (this) {
79 Map<K, V> newMap = new HashMap<K, V>(internalMap);
80 V val = newMap.put(key, value);
81 internalMap = newMap;
82 return val;
83 }
84 }
85
86 /**
87 * Removed the value and key from this map based on the
88 * provided key.
89 *
90 * @see java.util.Map#remove(java.lang.Object)
91 */
92 public V remove(Object key) {
93 synchronized (this) {
94 Map<K, V> newMap = new HashMap<K, V>(internalMap);
95 V val = newMap.remove(key);
96 internalMap = newMap;
97 return val;
98 }
99 }
100
101 /**
102 * Inserts all the keys and values contained in the
103 * provided map to this map.
104 *
105 * @see java.util.Map#putAll(java.util.Map)
106 */
107 public void putAll(Map<? extends K, ? extends V> newData) {
108 synchronized (this) {
109 Map<K, V> newMap = new HashMap<K, V>(internalMap);
110 newMap.putAll(newData);
111 internalMap = newMap;
112 }
113 }
114
115 /**
116 * Removes all entries in this map.
117 *
118 * @see java.util.Map#clear()
119 */
120 public void clear() {
121 synchronized (this) {
122 internalMap = new HashMap<K, V>();
123 }
124 }
125
126 // ==============================================
127 // ==== Below are methods that do not modify ====
128 // ==== the internal Maps ====
129 // ==============================================
130 /**
131 * Returns the number of key/value pairs in this map.
132 *
133 * @see java.util.Map#size()
134 */
135 public int size() {
136 return internalMap.size();
137 }
138
139 /**
140 * Returns true if this map is empty, otherwise false.
141 *
142 * @see java.util.Map#isEmpty()
143 */
144 public boolean isEmpty() {
145 return internalMap.isEmpty();
146 }
147
148 /**
149 * Returns true if this map contains the provided key, otherwise
150 * this method return false.
151 *
152 * @see java.util.Map#containsKey(java.lang.Object)
153 */
154 public boolean containsKey(Object key) {
155 return internalMap.containsKey(key);
156 }
157
158 /**
159 * Returns true if this map contains the provided value, otherwise
160 * this method returns false.
161 *
162 * @see java.util.Map#containsValue(java.lang.Object)
163 */
164 public boolean containsValue(Object value) {
165 return internalMap.containsValue(value);
166 }
167
168 /**
169 * Returns the value associated with the provided key from this
170 * map.
171 *
172 * @see java.util.Map#get(java.lang.Object)
173 */
174 public V get(Object key) {
175 return internalMap.get(key);
176 }
177
178 /**
179 * This method will return a read-only {@link Set}.
180 */
181 public Set<K> keySet() {
182 return internalMap.keySet();
183 }
184
185 /**
186 * This method will return a read-only {@link Collection}.
187 */
188 public Collection<V> values() {
189 return internalMap.values();
190 }
191
192 /**
193 * This method will return a read-only {@link Set}.
194 */
195 public Set<Entry<K, V>> entrySet() {
196 return internalMap.entrySet();
197 }
198
199 @Override
200 public Object clone() {
201 try {
202 return super.clone();
203 } catch (CloneNotSupportedException e) {
204 throw new InternalError();
205 }
206 }
207 }